home *** CD-ROM | disk | FTP | other *** search
- /* $Id: plctrl.c,v 1.26 1994/09/02 05:09:42 mjl Exp $
- * $Log: plctrl.c,v $
- * Revision 1.26 1994/09/02 05:09:42 mjl
- * Flush stdout before issuing error message, to be sure we are really on the
- * text screen.
- *
- * Revision 1.25 1994/08/25 04:08:09 mjl
- * Fixed limiting saturation value in a case that was affecting grayscale
- * output. Contributed by Radey Shouman. Also modified pltext/plgra to
- * return silently if plinit not yet called.
- *
- * Revision 1.24 1994/08/10 01:13:57 mjl
- * Fixed hardwired DOS/GNUSVGA directory location.
- *
- * Revision 1.23 1994/07/29 20:23:53 mjl
- * Added new function plLibOpen(), used for opening and returning the file
- * handle for "library" files -- font files, map files, etc. These are all
- * located by the same search path.
- *
- * Revision 1.22 1994/07/26 21:14:41 mjl
- * Improvements to the way PLplot looks for various files. Now more
- * consistent and flexible. In particular, environmentals can be set for
- * locations of each directory (for Tcl, binary, and library files).
- * Contributed by Mark Olesen.
- *
- * Revision 1.21 1994/07/25 06:44:31 mjl
- * Wrapped the include of unistd.h in a HAVE_UNISTD_H.
- *
- * Revision 1.20 1994/06/30 18:22:03 mjl
- * All core source files: made another pass to eliminate warnings when using
- * gcc -Wall. Lots of cleaning up: got rid of includes of math.h or string.h
- * (now included by plplot.h), and other minor changes. Now each file has
- * global access to the plstream pointer via extern; many accessor functions
- * eliminated as a result.
- */
-
- /* plctrl.c
-
- Misc. control routines, like begin, end, exit, change graphics/text
- mode, change color. Includes some spillage from plcore.c. If you
- don't know where it should go, put it here.
- */
-
- #include "plplotP.h"
-
- #ifdef __GO32__ /* dos386/djgpp */
- #ifdef __unix
- #undef __unix
- #endif
- #endif
-
- #ifdef __unix
- #include <sys/types.h>
- #include <sys/stat.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <errno.h>
- #endif
-
- /* Static functions */
-
- static void
- strcat_delim(char *dirspec);
-
- static int
- (*exit_handler) (char *errormsg);
-
- /* An additional hardwired location for lib files. */
- /* I have no plans to change these again, ever. */
-
- #if defined(AMIGA)
- #ifndef PLLIBDEV
- #define PLLIBDEV "plplot:lib"
- #endif
-
- #elif defined(GNU386)
- #ifndef PLLIBDEV
- #define PLLIBDEV "c:/plplot/lib"
- #endif
-
- #elif defined(MSDOS)
- #ifndef PLLIBDEV
- #define PLLIBDEV "c:\\plplot\\lib"
- #endif
-
- #elif defined (__riscos)
- #ifndef PLLIBDEV
- #define PLLIBDEV "$.plplot.lib"
- #endif
-
- #else
-
- /* Anything else is assumed to be Unix */
-
- #ifndef PLLIBDEV
- #define PLLIBDEV "/usr/local/plplot/lib"
- #endif
-
- #endif
-
- /*----------------------------------------------------------------------*\
- * Routines that deal with colors & color maps.
- \*----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------*\
- * plcol0()
- *
- * Set color, map 0. Argument is integer between 0 and 15.
- \*----------------------------------------------------------------------*/
-
- void
- c_plcol0(PLINT icol0)
- {
- if (plsc->level < 1) {
- plabort("plcol0: Please call plinit first");
- return;
- }
- if (icol0 < 0 || icol0 > 15) {
- plabort("plcol0: Invalid color.");
- return;
- }
- if (plsc->cmap0setcol[icol0] == 0) {
- plabort("plcol0: Requested color not allocated.");
- return;
- }
-
- plsc->icol0 = icol0;
- plsc->curcolor.r = plsc->cmap0[icol0].r;
- plsc->curcolor.g = plsc->cmap0[icol0].g;
- plsc->curcolor.b = plsc->cmap0[icol0].b;
-
- plsc->curcmap = 0;
- plP_state(PLSTATE_COLOR0);
- }
-
- /*----------------------------------------------------------------------*\
- * plcol1()
- *
- * Set color, map 1. Argument is a float between 0. and 1.
- \*----------------------------------------------------------------------*/
-
- void
- c_plcol1(PLFLT col1)
- {
- PLINT icol1;
-
- if (plsc->level < 1) {
- plabort("plcol1: Please call plinit first");
- return;
- }
- if (col1 < 0 || col1 > 1) {
- plabort("plcol1: Invalid color.");
- return;
- }
-
- icol1 = col1 * plsc->ncol1;
- icol1 = MIN(icol1, plsc->ncol1-1);
-
- plsc->icol1 = icol1;
- plsc->curcolor.r = plsc->cmap1[plsc->icol1].r;
- plsc->curcolor.g = plsc->cmap1[plsc->icol1].g;
- plsc->curcolor.b = plsc->cmap1[plsc->icol1].b;
-
- plsc->curcmap = 1;
- plP_state(PLSTATE_COLOR1);
- }
-
- /*----------------------------------------------------------------------*\
- * plscolbg()
- *
- * Set the background color (cmap0[0]) by 8 bit RGB value
- \*----------------------------------------------------------------------*/
-
- void
- c_plscolbg(PLINT r, PLINT g, PLINT b)
- {
- plscol0(0, r, g, b);
- }
-
- /*----------------------------------------------------------------------*\
- * plgcolbg()
- *
- * Returns the background color (cmap0[0]) by 8 bit RGB value
- \*----------------------------------------------------------------------*/
-
- void
- c_plgcolbg(PLINT *r, PLINT *g, PLINT *b)
- {
- plgcol0(0, r, g, b);
- }
-
- /*----------------------------------------------------------------------*\
- * plscol0()
- *
- * Set a given color from color map 0 by 8 bit RGB value
- * Does not result in any additional cells to be allocated.
- \*----------------------------------------------------------------------*/
-
- void
- c_plscol0(PLINT icol0, PLINT r, PLINT g, PLINT b)
- {
- if (icol0 < 0 || icol0 > 15) {
- plabort("plscol0: Illegal color table value");
- return;
- }
- if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
- plabort("plscol0: Invalid color");
- return;
- }
-
- plsc->cmap0[icol0].r = r;
- plsc->cmap0[icol0].g = g;
- plsc->cmap0[icol0].b = b;
- plsc->cmap0setcol[icol0] = 1;
-
- if (plsc->level > 0)
- plP_state(PLSTATE_CMAP0);
- }
-
- /*----------------------------------------------------------------------*\
- * plgcol0()
- *
- * Returns 8 bit RGB values for given color from color map 0
- * Values are negative if an invalid color id is given
- \*----------------------------------------------------------------------*/
-
- void
- c_plgcol0(PLINT icol0, PLINT *r, PLINT *g, PLINT *b)
- {
- *r = -1;
- *g = -1;
- *b = -1;
-
- if (icol0 < 0 || icol0 > 15) {
- plabort("plgcol0: Invalid color index");
- return;
- }
- if (plsc->cmap0setcol[icol0] == 0) {
- plabort("plgcol0: Requested color not allocated");
- return;
- }
-
- *r = plsc->cmap0[icol0].r;
- *g = plsc->cmap0[icol0].g;
- *b = plsc->cmap0[icol0].b;
-
- return;
- }
-
- /*----------------------------------------------------------------------*\
- * plscmap0n()
- *
- * Set number of colors in cmap 0
- * Must be <= 16, and the driver is not guaranteed to support all of these.
- \*----------------------------------------------------------------------*/
-
- void
- c_plscmap0n(PLINT ncol0)
- {
- if (ncol0 > 16 || ncol0 < 1) {
- plabort("plscmap0n: Number of colors must be between 1 and 16");
- return;
- }
-
- plsc->ncol0 = ncol0;
- }
-
- /*----------------------------------------------------------------------*\
- * plscmap1n()
- *
- * Set number of colors in cmap 1
- * Note that the driver is allowed to disregard this number.
- * In particular, most use far fewer.
- \*----------------------------------------------------------------------*/
-
- void
- c_plscmap1n(PLINT ncol1)
- {
- if (ncol1 > 256 || ncol1 < 1) {
- plabort("plscmap1n: Number of colors must be between 1 and 256");
- return;
- }
-
- plsc->ncol1 = ncol1;
- }
-
- /*----------------------------------------------------------------------*\
- * plscmap0()
- *
- * Set color map 0 colors by 8 bit RGB values
- * This also sets the number of colors.
- \*----------------------------------------------------------------------*/
-
- void
- c_plscmap0(PLINT *r, PLINT *g, PLINT *b, PLINT ncol0)
- {
- int i;
-
- if (ncol0 > 16 || ncol0 < 1) {
- plabort("plscmap0n: Number of colors must be between 1 and 16");
- return;
- }
- plsc->ncol0 = ncol0;
-
- for (i = 0; i < plsc->ncol0; i++) {
- if ((r[i] < 0 || r[i] > 255) ||
- (g[i] < 0 || g[i] > 255) ||
- (b[i] < 0 || b[i] > 255)) {
-
- fprintf(stderr, "plscmap0: Invalid RGB color: %d, %d, %d\n",
- (int) r[i], (int) g[i], (int) b[i]);
-
- plabort("plscmap0: Invalid color");
- return;
- }
-
- plsc->cmap0[i].r = r[i];
- plsc->cmap0[i].g = g[i];
- plsc->cmap0[i].b = b[i];
- plsc->cmap0setcol[i] = 1;
- }
-
- if (plsc->level > 0)
- plP_state(PLSTATE_CMAP0);
- }
-
- /*----------------------------------------------------------------------*\
- * plscmap1()
- *
- * Set color map 1 colors by 8 bit RGB values
- * This also sets the number of colors.
- \*----------------------------------------------------------------------*/
-
- void
- c_plscmap1(PLINT *r, PLINT *g, PLINT *b, PLINT ncol1)
- {
- int i;
-
- if (ncol1 > 256 || ncol1 < 1) {
- plabort("plscmap1n: Number of colors must be between 1 and 256");
- return;
- }
-
- plsc->ncol1 = ncol1;
-
- for (i = 0; i < plsc->ncol1; i++) {
- if ((r[i] < 0 || r[i] > 255) ||
- (g[i] < 0 || g[i] > 255) ||
- (b[i] < 0 || b[i] > 255)) {
-
- fprintf(stderr, "plscmap1: Invalid RGB color: %d, %d, %d\n",
- (int) r[i], (int) g[i], (int) b[i]);
-
- plabort("plscmap1: Invalid color");
- return;
- }
- plsc->cmap1[i].r = r[i];
- plsc->cmap1[i].g = g[i];
- plsc->cmap1[i].b = b[i];
- }
-
- plsc->cmap1set = 1;
- if (plsc->level > 0)
- plP_state(PLSTATE_CMAP1);
- }
-
- /*----------------------------------------------------------------------*\
- * plscmap1l()
- *
- * Set color map 1 colors using a piece-wise linear relationship between
- * position in the color map (from 0 to 1) and position in HLS or RGB color
- * space. May be called at any time.
- *
- * The idea here is to specify a number of control points that specify the
- * mapping between HLS (or RGB or CMY) and palette 1 value. Between these
- * points, linear interpolation is used. By mapping position in the color
- * map to function value, this gives a smooth variation of color with
- * intensity. Any number of control points may be specified, located at
- * arbitrary positions (intensities), although typically 2 - 4 are enough.
- * Another way of stating this is that we are traversing a given number of
- * lines through HLS (or RGB) space as we move through cmap 1 entries. The
- * control points at the minimum and maximum intensity (0 and 1) must
- * always be specified. By adding more control points you can get more
- * variation. One good technique for plotting functions that vary about
- * some expected average is to use an additional 2 control points in the
- * center (intensity ~= 0.5) that are the same color as the background
- * (typically white for paper output, black for crt), and same hue as the
- * boundary control points. This allows the highs and lows to be very
- * easily distinguished.
- *
- * Each control point must specify the position in cmap 1 as well as
- * three coordinates in HLS or RGB space. The first point MUST correspond
- * to position = 0, and the last to position = 1.
- *
- * Bounds on RGB coordinates:
- * R,G,B [0, 1] magnitude
- *
- * Bounds on HLS coordinates:
- * hue [0, 360] degrees
- * lightness [0, 1] magnitude
- * saturation [0, 1] magnitude
- *
- * The inputs are:
- * itype 0: HLS, 1: RGB
- * npts number of control points
- * pos[] position for each control point
- * coord1[] first coordinate for each control point
- * coord2[] second coordinate for each control point
- * coord3[] third coordinate for each control point
- \*----------------------------------------------------------------------*/
-
- void
- c_plscmap1l(PLINT itype, PLINT npts, PLFLT *pos,
- PLFLT *coord1, PLFLT *coord2, PLFLT *coord3)
- {
- int n;
- PLFLT h, l, s, r, g, b;
-
- if (npts < 2) {
- plabort("plscmap1l: Must specify at least two control points");
- return;
- }
-
- if ( (pos[0] != 0) || (pos[npts-1] != 1)) {
- plabort("plscmap1l: First, last control points must lie on boundary");
- return;
- }
-
- if ( npts > 32 ) {
- plabort("plscmap1l: Maximum of 32 control points allowed");
- return;
- }
-
- if (plsc->ncol1 == 0)
- plsc->ncol1 = 256;
-
- /* Save control points */
-
- plsc->ncp1 = npts;
-
- for (n = 0; n < npts; n++) {
-
- if (itype == 0) {
- h = coord1[n];
- l = coord2[n];
- s = coord3[n];
- }
- else {
- r = coord1[n];
- g = coord2[n];
- b = coord3[n];
- plRGB_HLS(r, g, b, &h, &l, &s);
- }
-
- plsc->cmap1cp[n].h = h;
- plsc->cmap1cp[n].l = l;
- plsc->cmap1cp[n].s = s;
- plsc->cmap1cp[n].p = pos[n];
- }
-
- /* Calculate and set color map */
-
- plcmap1_calc();
- }
-
- /*----------------------------------------------------------------------*\
- * plcmap1_calc()
- *
- * Bin up cmap 1 space and assign colors to make inverse mapping easy.
- * Always do interpolation in HLS space.
- \*----------------------------------------------------------------------*/
-
- void
- plcmap1_calc(void)
- {
- int i, n;
- PLFLT icmap1, delta;
- PLFLT h, l, s, r, g, b;
-
- for (n = 0; n < plsc->ncp1-1; n++) {
-
- if ( plsc->cmap1cp[n].p == plsc->cmap1cp[n+1].p )
- continue;
-
- for (i = 0; i < plsc->ncol1; i++) {
- icmap1 = (double) i / (plsc->ncol1 - 1.0);
- if ( (icmap1 < plsc->cmap1cp[n].p) ||
- (icmap1 > plsc->cmap1cp[n+1].p) )
- continue;
-
- delta = (icmap1 - plsc->cmap1cp[n].p) /
- (plsc->cmap1cp[n+1].p - plsc->cmap1cp[n].p);
-
- h = plsc->cmap1cp[n].h +
- (plsc->cmap1cp[n+1].h - plsc->cmap1cp[n].h) * delta;
- l = plsc->cmap1cp[n].l +
- (plsc->cmap1cp[n+1].l - plsc->cmap1cp[n].l) * delta;
- s = plsc->cmap1cp[n].s +
- (plsc->cmap1cp[n+1].s - plsc->cmap1cp[n].s) * delta;
-
- plHLS_RGB(h, l, s, &r, &g, &b);
-
- plsc->cmap1[i].r = MAX(0, MIN(255, (int) (256. * r)));
- plsc->cmap1[i].g = MAX(0, MIN(255, (int) (256. * g)));
- plsc->cmap1[i].b = MAX(0, MIN(255, (int) (256. * b)));
- }
- }
-
- plsc->cmap1set = 1;
- if (plsc->level > 0)
- plP_state(PLSTATE_CMAP1);
- }
-
- /*----------------------------------------------------------------------*\
- * color_def()
- *
- * Initializes color table entries by RGB values.
- * Does nothing if color already set.
- \*----------------------------------------------------------------------*/
-
- static void
- color_def(PLINT i, U_CHAR r, U_CHAR g, U_CHAR b)
- {
- if ( ! plsc->cmap0setcol[i] && i < plsc->ncol0) {
- plsc->cmap0[i].r = r;
- plsc->cmap0[i].g = g;
- plsc->cmap0[i].b = b;
- plsc->cmap0setcol[i] = 1;
- }
- }
-
- /*----------------------------------------------------------------------*\
- * plCmap0_init()
- *
- * Initializes color map 0.
- * Do not initialize if already done.
- *
- * Initial RGB values for color map 0 taken from HPUX 8.07 X-windows
- * rgb.txt file, and may not accurately represent the described colors on
- * all systems.
- *
- * Note the background color is not set, since the device driver may be
- * able to detect if a monochrome output device is being used, in which
- * case I want to choose the default background color there.
- \*----------------------------------------------------------------------*/
-
- void
- plCmap0_init(void)
- {
- if (plsc->ncol0 == 0)
- plsc->ncol0 = 16;
-
- /* Color map 0 */
- /* Any entries already filled by user or unallocated are not touched */
-
- color_def(0, 0, 0, 0); /* black */
- color_def(1, 255, 0, 0); /* red */
- color_def(2, 255, 255, 0); /* yellow */
- color_def(3, 0, 255, 0); /* green */
- color_def(4, 50, 191, 193); /* aquamarine */
- color_def(5, 255, 181, 197); /* pink */
- color_def(6, 245, 222, 179); /* wheat */
- color_def(7, 126, 126, 126); /* grey */
- color_def(8, 165, 42, 42); /* brown */
- color_def(9, 0, 0, 255); /* blue */
- color_def(10, 138, 43, 226); /* Blue Violet */
- color_def(11, 0, 255, 255); /* cyan */
- color_def(12, 25, 204, 223); /* turquoise */
- color_def(13, 255, 0, 255); /* magenta */
- color_def(14, 233, 150, 122); /* salmon */
- color_def(15, 255, 255, 255); /* white */
- }
-
- /*----------------------------------------------------------------------*\
- * plCmap1_init()
- *
- * Initializes color map 1.
- * Do not initialize if already done.
- *
- * The default initialization uses 4 control points in HLS space, the two
- * inner ones being very close to one of the vertices of the HLS double
- * cone. The vertex used (black or white) is chosen to be the closer to
- * the background color. If you don't like these settings you can always
- * initialize it yourself.
- \*----------------------------------------------------------------------*/
-
- void
- plCmap1_init(void)
- {
- PLFLT i[4], h[4], l[4], s[4], vertex;
-
- /* Return if the user has already filled color map */
-
- if (plsc->cmap1set)
- return;
-
- /* Positions of control points */
-
- i[0] = 0; /* left boundary */
- i[1] = 0.45; /* just before center */
- i[2] = 0.55; /* just after center */
- i[3] = 1; /* right boundary */
-
- /* For center control points, pick black or white, whichever is closer to bg */
- /* Be carefult to pick just short of top or bottom else hue info is lost */
-
- vertex = ((float) plsc->cmap0[0].r + (float) plsc->cmap0[0].g +
- (float) plsc->cmap0[0].b) / 3. / 255.;
-
- if (vertex < 0.5)
- vertex = 0.01;
- else
- vertex = 0.99;
-
- /* Set hue */
-
- h[0] = 260; /* low: blue-violet */
- h[1] = 260; /* only change as we go over vertex */
- h[2] = 0; /* high: red */
- h[3] = 0; /* keep fixed */
-
- /* Set lightness */
-
- l[0] = 0.5; /* low */
- l[1] = vertex; /* bg */
- l[2] = vertex; /* bg */
- l[3] = 0.5; /* high */
-
- /* Set saturation -- keep at maximum */
-
- s[0] = 1;
- s[1] = 1;
- s[2] = 1;
- s[3] = 1;
-
- c_plscmap1l(0, 4, i, h, l, s);
- }
-
- /*----------------------------------------------------------------------*\
- * plscolor()
- *
- * Used to globally turn color output on/off
- \*----------------------------------------------------------------------*/
-
- void
- c_plscolor(PLINT color)
- {
- plsc->colorset = 1;
- plsc->color = color;
- }
-
- /*----------------------------------------------------------------------*\
- * plrgb()
- *
- * Set line color by red, green, blue from 0. to 1.
- * Do NOT use this. Only retained for backward compatibility
- \*----------------------------------------------------------------------*/
-
- void
- c_plrgb(PLFLT r, PLFLT g, PLFLT b)
- {
- if (plsc->level < 1) {
- plabort("plrgb: Please call plinit first");
- return;
- }
-
- plsc->icol0 = PL_RGB_COLOR;
- plsc->curcolor.r = MAX(0, MIN(255, (int) (256. * r)));
- plsc->curcolor.g = MAX(0, MIN(255, (int) (256. * g)));
- plsc->curcolor.b = MAX(0, MIN(255, (int) (256. * b)));
-
- plsc->curcmap = 0;
- plP_state(PLSTATE_COLOR0);
- }
-
- /*----------------------------------------------------------------------*\
- * plrgb1()
- *
- * Set line color by 8 bit RGB values.
- * See note to plrgb()
- \*----------------------------------------------------------------------*/
-
- void
- c_plrgb1(PLINT r, PLINT g, PLINT b)
- {
- if (plsc->level < 1) {
- plabort("plrgb1: Please call plinit first");
- return;
- }
- if ((r < 0 || r > 255) || (g < 0 || g > 255) || (b < 0 || b > 255)) {
- plabort("plrgb1: Invalid color");
- return;
- }
-
- plsc->icol0 = PL_RGB_COLOR;
- plsc->curcolor.r = r;
- plsc->curcolor.g = g;
- plsc->curcolor.b = b;
-
- plsc->curcmap = 0;
- plP_state(PLSTATE_COLOR0);
- }
-
- /*----------------------------------------------------------------------*\
- * void plhls()
- *
- * Set current color by hue, lightness, and saturation.
- * Convert hls color coordinates to rgb, then call plrgb.
- * See note to plrgb()
- \*----------------------------------------------------------------------*/
-
- void
- c_plhls(PLFLT h, PLFLT l, PLFLT s)
- {
- PLFLT r, g, b;
-
- plHLS_RGB(h, l, s, &r, &g, &b);
- plrgb(r, g, b);
- }
-
- /*----------------------------------------------------------------------*\
- * void value()
- *
- * Auxiliary function used by plHLS_RGB().
- \*----------------------------------------------------------------------*/
-
- static float
- value(double n1, double n2, double hue)
- {
- float val;
-
- while (hue >= 360.)
- hue -= 360.;
- while (hue < 0.)
- hue += 360.;
-
- if (hue < 60.)
- val = n1 + (n2 - n1) * hue / 60.;
- else if (hue < 180.)
- val = n2;
- else if (hue < 240.)
- val = n1 + (n2 - n1) * (240. - hue) / 60.;
- else
- val = n1;
-
- return (val);
- }
-
- /*----------------------------------------------------------------------*\
- * void plHLS_RGB()
- *
- * Convert HLS color to RGB color.
- * Bounds on HLS (input):
- * hue [0., 360.] degrees
- * lightness [0., 1.] magnitude
- * saturation [0., 1.] magnitude
- *
- * Hue is always mapped onto the interval [0., 360.] regardless of input.
- * Bounds on RGB (output) is always [0., 1.]. Convert to RGB color values
- * by multiplying by 2**nbits (nbits typically 8).
- \*----------------------------------------------------------------------*/
-
- void
- plHLS_RGB(PLFLT h, PLFLT l, PLFLT s, PLFLT *p_r, PLFLT *p_g, PLFLT *p_b)
- {
- float m1, m2;
-
- if (l <= .5)
- m2 = l * (s + 1.);
- else
- m2 = l + s - l * s;
-
- m1 = 2 * l - m2;
-
- *p_r = value(m1, m2, h + 120.);
- *p_g = value(m1, m2, h);
- *p_b = value(m1, m2, h - 120.);
- }
-
- /*----------------------------------------------------------------------*\
- * void plRGB_HLS()
- *
- * Convert RGB color to HLS color.
- * Bounds on RGB (input) is always [0., 1.].
- * Bounds on HLS (output):
- * hue [0., 360.] degrees
- * lightness [0., 1.] magnitude
- * saturation [0., 1.] magnitude
- \*----------------------------------------------------------------------*/
-
- void
- plRGB_HLS(PLFLT r, PLFLT g, PLFLT b, PLFLT *p_h, PLFLT *p_l, PLFLT *p_s)
- {
- PLFLT h, l, s, d, rc, gc, bc, rgb_min, rgb_max;
-
- rgb_min = MIN( r, MIN( g, b ));
- rgb_max = MAX( r, MAX( g, b ));
-
- l = (rgb_min+rgb_max) / 2.0;
-
- if (rgb_min == rgb_max) {
- s = 0;
- h = 0;
- }
- else {
- d = rgb_max - rgb_min;
- if (l < 0.5)
- s = 0.5 * d / l;
- else
- s = 0.5* d / (1.-l);
-
- rc = (rgb_max-r) / d;
- gc = (rgb_max-g) / d;
- bc = (rgb_max-b) / d;
-
- if (r == rgb_max)
- h = bc-gc;
- else if (g == rgb_max)
- h = rc-bc+2;
- else
- h = gc-rc-2;
-
- h = h*60;
- if (h < 0)
- h = h+360;
- else if (h >= 360)
- h = h-360;
- }
- *p_h = h;
- *p_l = l;
- *p_s = s;
- }
-
- /*----------------------------------------------------------------------*\
- * A grab-bag of various control routines.
- \*----------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------*\
- * void plwarn()
- *
- * A handy way to issue warnings, if need be.
- \*----------------------------------------------------------------------*/
-
- void
- plwarn(char *errormsg)
- {
- int was_gfx = 0;
-
- if (plsc->graphx == 1) {
- was_gfx = 1;
- pltext();
- }
-
- fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
- if (*errormsg != '\0')
- fprintf(stderr, "%s\n", errormsg);
-
- if (was_gfx == 1)
- plgra();
- }
-
- /*----------------------------------------------------------------------*\
- * void plabort()
- *
- * Exactly the same as plwarn(), but appends ", aborting operation" to the
- * error message. Helps to keep source code uncluttered and provides a
- * convention for error aborts.
- \*----------------------------------------------------------------------*/
-
- void
- plabort(char *errormsg)
- {
- int was_gfx = 0;
-
- if (plsc->graphx == 1) {
- was_gfx = 1;
- pltext();
- }
-
- fprintf(stderr, "\n*** PLPLOT WARNING ***\n");
- if (*errormsg != '\0')
- fprintf(stderr, "%s, aborting operation\n", errormsg);
-
- if (was_gfx == 1)
- plgra();
- }
-
- /*----------------------------------------------------------------------*\
- * void plexit()
- *
- * In case of an abort this routine is called. It just prints out an error
- * message and tries to clean up as much as possible. It's best to turn
- * off pause and then restore previous setting before returning.
- *
- * If cleanup needs to be done in the main program, the user should write
- * his/her own exit handler and pass it in via plsexit(). This function
- * should should either call plend() before exiting, or simply return.
- \*----------------------------------------------------------------------*/
-
- void
- plexit(char *errormsg)
- {
- int status = 1;
-
- if (exit_handler != NULL)
- status = (*exit_handler)(errormsg);
-
- plsc->nopause = 1;
- plend();
- if (*errormsg != '\0') {
- fprintf(stderr, "\n*** PLPLOT ERROR ***\n");
- fprintf(stderr, "%s\n", errormsg);
- }
-
- fprintf(stderr, "Program aborted\n");
- exit(status);
- }
-
- /*----------------------------------------------------------------------*\
- * void plsexit()
- *
- * Sets an optional user exit handler.
- \*----------------------------------------------------------------------*/
-
- void
- plsexit(int (*handler) (char *))
- {
- exit_handler = handler;
- }
-
- /*----------------------------------------------------------------------*\
- * void plgra()
- *
- * Switches to graphics screen.
- *
- * Here and in pltext() it's a good idea to return silently if plinit()
- * hasn't yet been called, since plwarn() calls pltext() and plgra(), and
- * plwarn() may be called at any time.
- \*----------------------------------------------------------------------*/
-
- void
- c_plgra(void)
- {
- if (plsc->level > 0)
- plP_esc(PLESC_GRAPH, NULL);
- }
-
- /*----------------------------------------------------------------------*\
- * void pltext()
- *
- * Switches to text screen.
- \*----------------------------------------------------------------------*/
-
- void
- c_pltext(void)
- {
- if (plsc->level > 0) {
- plP_esc(PLESC_TEXT, NULL);
- plflush();
- }
- }
-
- /*----------------------------------------------------------------------*\
- * void pl_cmd()
- *
- * Front-end to driver escape function.
- * In principle this can be used to pass just about anything directly
- * to the driver.
- \*----------------------------------------------------------------------*/
-
- void
- pl_cmd(PLINT op, void *ptr)
- {
- plP_esc(op, ptr);
- }
-
- /*----------------------------------------------------------------------*\
- * char *plFindCommand
- *
- * Looks for the specified executable file. Search path:
- * PLPLOT_BIN_ENV = $(PLPLOT_BIN)
- * current directory
- * PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin
- * BIN_DIR
- *
- * The caller must free the returned pointer (points to malloc'ed memory)
- * when finished with it.
- \*----------------------------------------------------------------------*/
-
- char *
- plFindCommand(char *fn)
- {
- char *fs = NULL, *dn;
-
- /* PLPLOT_BIN_ENV = $(PLPLOT_BIN) */
-
- #if defined(PLPLOT_BIN_ENV)
- if ((dn = getenv(PLPLOT_BIN_ENV)) != NULL) {
- plGetName(dn, "", fn, &fs);
- if ( ! plFindName(fs))
- return fs;
- fprintf(stderr, PLPLOT_BIN_ENV"=\"%s\"\n", dn); /* what IS set? */
- }
- #endif /* PLPLOT_BIN_ENV */
-
- /* Current directory */
-
- plGetName(".", "", fn, &fs);
- if ( ! plFindName(fs))
- return fs;
-
- /* PLPLOT_HOME_ENV/bin = $(PLPLOT_HOME)/bin */
-
- #if defined(PLPLOT_HOME_ENV)
- if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
- plGetName(dn, "bin", fn, &fs);
- if ( ! plFindName(fs))
- return fs;
- fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
- }
- #endif /* PLPLOT_HOME_ENV */
-
- /* BIN_DIR */
-
- #if defined (BIN_DIR)
- plGetName(BIN_DIR, "", fn, &fs);
- if ( ! plFindName(fs))
- return fs;
- #endif
-
- /* Crapped out */
-
- free_mem(fs);
- fprintf(stderr, "plFindCommand: cannot locate command: %s\n", fn);
- #if defined (BIN_DIR)
- fprintf(stderr, "bin dir=\"" BIN_DIR "\"\n" ); /* what WAS set? */
- #endif /* BIN_DIR */
- return NULL;
- }
-
- /*----------------------------------------------------------------------*\
- * FILE *plLibOpen(fn)
- *
- * Return file pointer to lib file.
- * Locations checked:
- * PLPLOT_LIB_ENV = $(PLPLOT_LIB)
- * current directory
- * PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib
- * LIB_DIR
- * PLLIBDEV
- \*----------------------------------------------------------------------*/
-
- FILE *
- plLibOpen(char *fn)
- {
- FILE *file;
- char *fs = NULL, *dn = NULL;
-
- /**** search PLPLOT_LIB_ENV = $(PLPLOT_LIB) ****/
-
- #if defined(PLPLOT_LIB_ENV)
- if ((dn = getenv(PLPLOT_LIB_ENV)) != NULL) {
- plGetName(dn, "", fn, &fs);
-
- if ((file = fopen(fs, "rb")) != NULL)
- goto done;
-
- fprintf(stderr, PLPLOT_LIB_ENV"=\"%s\"\n", dn); /* what IS set? */
- }
- #endif /* PLPLOT_LIB_ENV */
-
- /**** search current directory ****/
-
- if ((file = fopen(fn, "rb")) != NULL)
- goto done;
-
- /**** search PLPLOT_HOME_ENV/lib = $(PLPLOT_HOME)/lib ****/
-
- #if defined (PLPLOT_HOME_ENV)
- if ((dn = getenv(PLPLOT_HOME_ENV)) != NULL) {
- plGetName(dn, "lib", fn, &fs);
-
- if ((file = fopen(fs, "rb")) != NULL)
- goto done;
- fprintf(stderr, PLPLOT_HOME_ENV"=\"%s\"\n",dn); /* what IS set? */
- }
- #endif /* PLPLOT_HOME_ENV/lib */
-
- /**** search installed location ****/
-
- #if defined (LIB_DIR)
- plGetName(LIB_DIR, "", fn, &fs);
-
- if ((file = fopen(fs, "rb")) != NULL)
- goto done;
- #endif /* LIB_DIR */
-
- /**** search hardwired location ****/
-
- #ifdef PLLIBDEV
- plGetName(PLLIBDEV, "", fn, &fs);
-
- if ((file = fopen(fs, "rb")) != NULL)
- goto done;
- #endif /* PLLIBDEV */
-
- /**** not found, give up ****/
-
- pltext();
- fprintf(stderr, "\nCannot open library file: %s\n", fn);
- #if defined (LIB_DIR)
- fprintf(stderr, "lib dir=\"" LIB_DIR "\"\n" ); /* what WAS set? */
- #endif /* LIB_DIR */
- plgra();
- return NULL;
-
- done:
- free_mem(fs);
- return (file);
- }
-
- /*----------------------------------------------------------------------*\
- * int plFindName
- *
- * Authors: Paul Dubois (LLNL), others?
- * This function is in the public domain.
- *
- * Given a pathname, determine if it is a symbolic link. If so, continue
- * searching to the ultimate terminus - there may be more than one link.
- * Use the error value to determine when the terminus is reached, and to
- * determine if the pathname really exists. Then stat it to determine
- * whether it's executable. Return 0 for an executable, errno otherwise.
- * Note that 'p' _must_ have at least one '/' character - it does by
- * construction in this program. The contents of the array pointed to by
- * 'p' are changed to the actual pathname if findname is successful.
- *
- * This function is only defined under Unix for now.
- \*----------------------------------------------------------------------*/
-
- #ifdef __unix
- int
- plFindName(char *p)
- {
- int n;
- char buf[1024], *cp;
- extern int errno;
- struct stat sbuf;
-
- while ((n = readlink(p, buf, 1024)) > 0) {
- #ifdef DEBUG
- fprintf(stderr, "Readlink read %d chars at: %s\n", n, p);
- #endif
- if (buf[0] == '/') { /* Link is an absolute path */
- strncpy(p, buf, n);
- p[n] = '\0';
- #ifdef DEBUG
- fprintf(stderr, "Link is absolute: %s\n", p);
- #endif
- }
- else { /* Link is relative to its directory; make it
- absolute */
- cp = 1 + strrchr(p, '/');
- strncpy(cp, buf, n);
- cp[n] = '\0';
- #ifdef DEBUG
- fprintf(stderr, "Link is relative: %s\n\tTotal path: %s\n", cp, p);
- #endif
- }
- }
-
- /* SGI machines return ENXIO instead of EINVAL Dubois 11/92 */
-
- if (errno == EINVAL || errno == ENXIO) {
- #ifdef DEBUG
- fprintf(stderr, "%s may be the one ...", p);
- #endif
- #ifdef SX
- #define S_ISREG(mode) (mode & S_IFREG)
- #endif
- if ((stat(p, &sbuf) == 0) && S_ISREG(sbuf.st_mode)) {
- #ifdef DEBUG
- fprintf(stderr, "regular file\n");
- #endif
- return (access(p, X_OK));
- }
- }
- #ifdef DEBUG
- fprintf(stderr, "not executable\n");
- #endif
- return (errno ? errno : -1);
- }
-
- #else
- int
- plFindName(char *p)
- {
- return 1;
- }
- #endif
-
- /*----------------------------------------------------------------------*\
- * void plGetName()
- *
- * Gets search name for file by concatenating the dir, subdir, and file
- * name, allocating memory as needed. The appropriate delimiter is added
- * after the dir specification as necessary. The caller is responsible
- * for freeing the malloc'ed memory.
- \*----------------------------------------------------------------------*/
-
- void
- plGetName(char *dir, char *subdir, char *filename, char **filespec)
- {
- int lfilespec;
-
- /* Malloc space for filespec */
-
- free_mem(*filespec);
- lfilespec = 10;
- lfilespec = strlen(dir) + strlen(subdir) + strlen(filename) + 10;
- *filespec = (char *) malloc(lfilespec);
-
- strcpy(*filespec, dir);
-
- if (*subdir != '\0') {
- strcat_delim(*filespec);
- strcat(*filespec, subdir);
- }
- if (*filename != '\0') {
- strcat_delim(*filespec);
- strcat(*filespec, filename);
- }
- }
-
- /*----------------------------------------------------------------------*\
- * void strcat_delim()
- *
- * Append path name deliminator if necessary (does not add one if one's
- * there already, or if dealing with a colon-terminated device name as
- * used on the Amiga).
- \*----------------------------------------------------------------------*/
-
- static void
- strcat_delim(char *dirspec)
- {
- int ldirspec = strlen(dirspec);
- #if defined (MSDOS)
- if (dirspec[ldirspec-1] != '\\')
- strcat(dirspec, "\\");
- #elif defined (AMIGA)
- if (dirspec[ldirspec-1] != '/' && dirspec[ldirspec-1] != ':')
- strcat(dirspec, "/");
- #elif defined (__riscos)
- if (dirspec[ldirspec-1] != '.')
- strcat(dirspec, ".");
- #else /* unix is the default */
- if (dirspec[ldirspec-1] != '/')
- strcat(dirspec, "/");
- #endif
- }
-
- /*----------------------------------------------------------------------*\
- * plGetInt()
- *
- * Prompts human to input an integer in response to given message.
- \*----------------------------------------------------------------------*/
-
- PLINT
- plGetInt(char *s)
- {
- int m;
- int i = 0;
- char line[256];
-
- while (i++ < 10) {
- fprintf(stdout, s);
- fgets(line, sizeof(line), stdin);
- #ifdef MSDOS
- m = atoi(line);
- return (m);
- #else
- if (sscanf(line, "%d", &m) == 1)
- return (m);
- fprintf(stdout, "No value or value out of range; please try again\n");
- #endif
- }
- plexit("Too many tries.");
- return (0);
- }
-
- /*----------------------------------------------------------------------*\
- * plGetFlt()
- *
- * Prompts human to input a float in response to given message.
- \*----------------------------------------------------------------------*/
-
- PLFLT
- plGetFlt(char *s)
- {
- PLFLT m;
- int i = 0;
- char line[256];
-
- while (i++ < 10) {
- fprintf(stdout, s);
- fgets(line, sizeof(line), stdin);
- #ifdef MSDOS
- m = atof(line);
- return (m);
- #else
- if (sscanf(line, "%f", &m) == 1)
- return (m);
- fprintf(stdout, "No value or value out of range; please try again\n");
- #endif
- }
- plexit("Too many tries.");
- return (0.);
- }
-